import * as Cesium from 'cesium'
type Options = {
    color?: Cesium.Color
    speed?: number,
    percent?: number,
    gradient?: number
}
class LineFlowMaterialProperty {
    _definitionChanged:any
    color:any
    speed:any
    percent:any
    gradient:any
    constructor(options:Options) {
        this._definitionChanged = new Cesium.Event();
        this.color = new Cesium.ConstantProperty(options.color);
        this.speed = new Cesium.ConstantProperty(options.speed);
        this.percent = new Cesium.ConstantProperty(options.percent);
        this.gradient =new Cesium.ConstantProperty(options.gradient);
    }

    get isConstant() {
        return false
    }

    get definitionChanged() {
        return this._definitionChanged;
    }

    getType() {
        return 'LineFlowMaterialType';
    }
     
    getValue(time:Cesium.JulianDate, result:Options) {
        if (!Cesium.defined(result)) { result = {} }
        let property = (Cesium.Property) as any;
        let [defaultColor,defaultSpeed,defaultPercent,defaultGradient ] = [Cesium.Color.BLUE, 5.0, 1.0, 0.4]
        result.color = property.getValueOrDefault(this.color, time, defaultColor, result.color)
        result.speed = property.getValueOrDefault(this.speed, time, defaultSpeed, result.speed)
        result.percent = property.getValueOrDefault(this.percent, time, defaultPercent, result.percent)
        result.gradient = property.getValueOrDefault(this.gradient, time, defaultGradient, result.gradient)
        return result
    }

    equals(other: typeof this) {
        let property = (Cesium.Property) as any
        return (
            this == other ||
            (
                property.equals(this.color, other.color)&&
                property.equals(this.speed, other.speed)&&
                property.equals(this.percent, other.percent)&&
                property.equals(this.gradient, other.gradient)
            )
        )
    }
}

export default function createLineFlowMaterial() {
    let CesiumMaterial = (Cesium.Material) as any
    CesiumMaterial.LineFlowMaterialProperty = LineFlowMaterialProperty
    CesiumMaterial.LineFlowMaterialType = 'LineFlowMaterialType';
    CesiumMaterial.LineFlowMaterialSource = `
        uniform vec4 color;
        uniform float speed;
        uniform float percent;
        uniform float gradient;

        czm_material czm_getMaterial(czm_materialInput materialInput){
            czm_material material = czm_getDefaultMaterial(materialInput);
            vec2 st = materialInput.st;
            float t =fract(czm_frameNumber * speed / 1000.0);
            t *= (1.0 + percent);
            float alpha = smoothstep(t- percent, t, st.s) * step(-t, -st.s);
            alpha += gradient;
            material.diffuse = color.rgb;
            material.alpha = alpha;
            return material;
        }
    `
    CesiumMaterial._materialCache.addMaterial(CesiumMaterial.LineFlowMaterialType, {
        fabric: {
            type: CesiumMaterial.LineFlowMaterialType,
            uniforms: {
                color: new Cesium.Color(1.0, 0.0, 0.0, 1.0),
                speed: 10.0,
                percent: 0.1,
                gradient: 0.01
            },
            source: CesiumMaterial.LineFlowMaterialSource
        },
        translucent: () => true
    })
}